package math.geom2d;

import math.base.CCS2d;
import math.base.Point2d;
import math.base.Vector2d;
import math.geomUtils.CurveType;

/**
 * @author Saga
 *
 */
public class Parabola2d extends ConicalCurve2d {
    public Parabola2d(final CCS2d _pos, final double _focus) {
        this.pos = _pos;

        if (_focus < 0.0) {
            throw new ArithmeticException("");
        }
        this.focus = _focus;
    }

    @Override
    public final CurveType getCurveType() {
        return CurveType.PARABOLA;
    }

    @Override
    public final void reverse() {
        this.pos.yReverse();
    }

    @Override
    public final Curve2d reversed() {
        return new Parabola2d(this.pos.yReversed(), this.focus);
    }

    @Override
    public final boolean isPeriodic() {
        return false;
    }

    @Override
    public final double getPeriod() {
        throw new ArithmeticException("");
    }

    @Override
    public final double getFirstParameter() {
        return Double.NEGATIVE_INFINITY;
    }

    @Override
    public final double getLastParameter() {
        return Double.POSITIVE_INFINITY;
    }

    @Override
    public final Point2d calcValue(final double _param) {
        return new Point2d(_param * _param * 0.25 / this.focus, _param);
    }

    @Override
    public final Vector2d calcDerivative(final double _param) {
        return new Vector2d(_param * 0.5 / this.focus, _param);
    }

    @Override
    public final Vector2d calcDerivativeN(final double _param, final int _order) {
        if (_order < 1) {
            throw new ArithmeticException("");
        } else if (_order == 1) {
            return new Vector2d(_param * 0.5 / this.focus, 1.0);
        } else if (_order == 2) {
            return new Vector2d(0.5 / this.focus, 0.0);
        } else {
            return new Vector2d();
        }
    }

    @Override
    public final void calcValueAndDerivative1(final double _param, final Point2d _pt,
            final Vector2d _der1) {
        _pt.init(_param * _param * 0.25 / this.focus, _param);
        _der1.init(_param * 0.5 / this.focus, 1.0);
    }

    @Override
    public final void calcValueAndDerivative2(final double _param, final Point2d _pt,
            final Vector2d _der1, final Vector2d _der2) {
        _pt.init(_param * _param * 0.25 / this.focus, _param);
        _der1.init(_param * 0.5 / this.focus, 1.0);
        _der2.init(0.5 / this.focus, 0.0);
    }

    @Override
    public final void calcValueAndDerivative3(final double _param, final Point2d _pt,
            final Vector2d _der1, final Vector2d _der2, final Vector2d _der3) {
        _pt.init(_param * _param * 0.25 / this.focus, _param);
        _der1.init(_param * 0.5 / this.focus, 1.0);
        _der2.init(0.5 / this.focus, 0.0);
        _der3.init(0.0, 0.0);
    }

    @Override
    public final Parabola2d clone() {
        return new Parabola2d(this.pos.clone(), this.focus);
    }

    private final double focus;
}
